-module(median).
-export([addFragmentsToMedianStruct/3, new/0, start/3, getList/1, getSum/1, getCount/1, getFragmentIds/1]).

%Struct is a tuple that contains Count,  group of 5 medians, and medians of medians
new() ->
  {0, [], []}.

start(Id, Neighbors, MedianStruct) ->
  random:seed(now()),
    case gossipprob:getGossipNode(Neighbors) of
      {ok, Node} ->
            Node ! {median, MedianStruct};
        {error, _Msg} ->
        ok
    end,
    ok.

addFragmentsToMedianStruct([], _Dict, MedianStruct) ->
  MedianStruct;
addFragmentsToMedianStruct(Keys, Dict, MedianStruct) ->
    FragId = hd(Keys),
    case hasFragmentId(FragId, MedianStruct) of
        false ->
            Count = element(1, MedianStruct),
            case Count > 5 of
                true ->
                    FiveMedians = element(2, MedianStruct),
                    SortedFive  = lists:sort(FiveMedians),
                    MedianOfMedian = lists:nth(3, SortedFive),
                    MedianOfMedianList = element(3, MedianStruct),
                    case lists:member(MedianOfMedian, MedianOfMedianList) of
                        false ->                          
                            NewMedianOfMedianList = lists:append(MedianOfMedianList,[MedianOfMedian]);
                        true ->
                            NewMedianOfMedianList = MedianOfMedianList
                    end,
                    NewMedianStruct = {0, [], NewMedianOfMedianList};
                false ->
                    NewCount = Count + 1,
                    MedianOfMedianList = element(3, MedianStruct),
                    FloatList = dict:fetch(FragId, Dict),
                    SortedList = lists:sort(FloatList),
                    Median = lists:nth(3, SortedList),
                    CurrentList = element(2, MedianStruct),                
                    NewMedianList = lists:append(CurrentList, [Median]),                           
                    NewMedianStruct = {NewCount, NewMedianList, MedianOfMedianList}
            end;
        true ->
          NewMedianStruct = MedianStruct
    end,
    addFragmentsToMedianStruct(tl(Keys), Dict, NewMedianStruct).

getList(MedianStruct) ->
    MedianOfMedianList = element(3, MedianStruct),
    SortedList = lists:sort(MedianOfMedianList),
    ListLength = length(MedianOfMedianList),
    Half = round(ListLength/2),    
    Median = lists:nth(Half, SortedList),
    Sublist = [Median].

getSum(MedianStruct) ->
  element(1, MedianStruct).
  
getCount(MedianStruct) ->
  element(2, MedianStruct).

hasFragmentId(Id, MedianStruct) ->
  lists:member(Id, getFragmentIds(MedianStruct)).
  
getFragmentIds(MedianStruct) ->
  element(3, MedianStruct).